﻿/*********************************************************************************
**                                                                              **
**  Copyright (C) 2024-2025 LiLong                                              **
**  This file is part of OpenVisaApplication.                                   **
**                                                                              **
**  OpenVisaApplication is free software: you can redistribute it and/or modify **
**  it under the terms of the GNU General Public License as published by        **
**  the Free Software Foundation, either version 3 of the License, or           **
**  (at your option) any later version.                                         **
**                                                                              **
**  OpenVisaApplication is distributed in the hope that it will be useful,      **
**  but WITHOUT ANY WARRANTY; without even the implied warranty of              **
**  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               **
**  GNU General Public License for more details.                                **
**                                                                              **
**  You should have received a copy of the GNU General Public License           **
**  along with OpenVisaApplication. If not, see <https://www.gnu.org/licenses/>.**
**********************************************************************************/
#include "MainWindow.h"
#include "About/AboutOpenVisaApplicationDialog.h"
#include "About/AboutOpenVisaDialog.h"
#include "About/AboutQCustomUiDialog.h"
#include "DeviceListView.h"
#include "IOTrace/IOTraceView.h"
#include "TestView/TestView.h"
#include "Update/UpdateDialog.h"
#include "Update/VersionCheck.h"

#include <AppCore/Device.h>
#include <AppCore/DeviceGroup.h>
#include <OpenVisa/Object.h>
#include <QCustomUi/QCtmMessageBox.h>

#include <QApplication>
#include <QCloseEvent>

struct MainWindow::Impl
{
    DeviceListView* deviceListView { nullptr };
    QWidget* emptyWidget { nullptr };
    std::map<std::shared_ptr<AppCore::DeviceItem>, QWidget*> pages;
    IOTraceView ioTrace;
};

MainWindow::MainWindow() : m_impl(std::make_unique<Impl>())
{
    ui.setupUi(this->centralWidget());
    init();
}

MainWindow::~MainWindow() {}

void MainWindow::init()
{
    setMinimumSize(800, 600);
    auto menuBar = this->menuBar();

    auto toolMenu = menuBar->addMenu(QStringLiteral("工具(&T)"));
    toolMenu->addAction(QStringLiteral("IO Trace"), this, [this] { m_impl->ioTrace.show(); });

    auto helpMenu = menuBar->addMenu(QStringLiteral("帮助(&H)"));
    helpMenu->addAction(QStringLiteral("关于 OpenVisaApplication"), this, [this] { AboutOpenVisaApplicationDialog(this).exec(); });
    helpMenu->addAction(QStringLiteral("关于 OpenVisa"), this, [this] { AboutOpenVisaDialog(this).exec(); });
    helpMenu->addAction(QStringLiteral("关于 QCustomUi"), this, [this] { AboutQCustomUiDialog(this).exec(); });
    helpMenu->addAction(QStringLiteral("关于 Qt"), this, &QApplication::aboutQt);
    helpMenu->addAction(QStringLiteral("检查更新"), this, &MainWindow::onUpdateAction);

    m_impl->deviceListView = new DeviceListView(this);
    ui.deviceListLayout->addWidget(m_impl->deviceListView);
    ui.splitter->setStretchFactor(1, 1);
    ui.deviceViewTabWidget->setTabsClosable(true);
    ui.deviceViewTabWidget->setAttribute(Qt::WA_StyledBackground);
    connect(m_impl->deviceListView, &DeviceListView::openDevice, this, &MainWindow::onOpenDevice);
    connect(m_impl->deviceListView, &DeviceListView::onlyShowView, this, &MainWindow::onOnlyShowView);
    connect(m_impl->deviceListView, &DeviceListView::closeDevice, this, &MainWindow::onCloseDevice);
    connect(ui.deviceViewTabWidget, &QTabWidget::tabCloseRequested, this, &MainWindow::onTabCloseRequested);
    auto& verCheck = VersionCheck::instance();
    connect(&verCheck,
            &VersionCheck::errorOccurred,
            this,
            [this](bool manual, const QString& error)
            {
                if (manual)
                    QCtmMessageBox::warning(this, u8"错误", error);
            });
    connect(&verCheck, &VersionCheck::finished, this, &MainWindow::onNewVersionArrived);
}

void MainWindow::openView(std::shared_ptr<AppCore::DeviceItem> item)
{
    auto device = dynamic_pointer_cast<AppCore::Device>(item);
    if (!device)
        return;

    if (auto it = m_impl->pages.find(device); it != m_impl->pages.end())
    {
        ui.deviceViewTabWidget->setCurrentWidget(it->second);
        return;
    }
    auto view = new TestView(device, this);
    ui.deviceViewTabWidget->addTab(view, item->name());
    ui.deviceViewTabWidget->setCurrentWidget(view);
    m_impl->pages.insert(std::pair<std::shared_ptr<AppCore::DeviceItem>, QWidget*> { device, view });
}

void MainWindow::onOpenDevice(std::shared_ptr<AppCore::DeviceItem> item)
{
    auto device = dynamic_pointer_cast<AppCore::Device>(item);
    if (!device)
        return;

    if (auto it = m_impl->pages.find(device); it != m_impl->pages.end())
    {
        ui.deviceViewTabWidget->setCurrentWidget(it->second);
        return;
    }

    try
    {
        device->object()->connect(device->address().toStdString());
    }
    catch (const std::exception& e)
    {
        QCtmMessageBox::critical(this, u8"错误", QString::fromLocal8Bit(e.what()));
        return;
    }
    openView(item);
}

void MainWindow::onOnlyShowView(std::shared_ptr<AppCore::DeviceItem> item) { openView(item); }

void MainWindow::onCloseDevice(std::shared_ptr<AppCore::DeviceItem> item)
{
    if (auto it = m_impl->pages.find(item); it != m_impl->pages.end())
    {
        auto index = ui.deviceViewTabWidget->indexOf(it->second);
        if (index < 0)
            return;
        ui.deviceViewTabWidget->removeTab(index);
    }
}

void MainWindow::onTabCloseRequested(int index)
{
    auto w = ui.deviceViewTabWidget->widget(index);
    ui.deviceViewTabWidget->removeTab(index);
    if (auto view = qobject_cast<TestView*>(w); view)
    {
        m_impl->pages.erase(view->device());
    }
    w->deleteLater();
}

void MainWindow::onUpdateAction() { VersionCheck::instance().checkUpdate(true); }

void MainWindow::onNewVersionArrived(bool manual, bool newVersion)
{
    if (newVersion || manual)
    {
        UpdateDialog dlg(this);
        auto& v = VersionCheck::instance();
        dlg.setDatas(v.version(), v.description(), v.downloadUrl(), !newVersion);
        dlg.exec();
    }
}

void MainWindow::closeEvent(QCloseEvent* event)
{
    if (!qApp->property("_force_quit").toBool())
    {
        if (QCtmMessageBox::question(this, u8"退出程序确认", u8"您确定要关闭程序吗？") != QCtmMessageBox::Yes)
        {
            event->ignore();
            return;
        }
        m_impl->ioTrace.close();
    }
    else
        m_impl->ioTrace.close();

    QCtmWindow::closeEvent(event);
}
